//
// Created by ttai on 2021/12/20.
//

#ifndef SM4_ALGORITHM_SM4_H
#define SM4_ALGORITHM_SM4_H

#include "bitset"
#include "string"
#include "BitOperation.h"

using namespace std;
static const string SboxTable[16][16] =
        {
                {"d6", "90", "e9", "fe", "cc", "e1", "3d", "b7", "16", "b6", "14", "c2", "28", "fb", "2c", "05"},
                {"2b", "67", "9a", "76", "2a", "be", "04", "c3", "aa", "44", "13", "26", "49", "86", "06", "99"},
                {"9c", "42", "50", "f4", "91", "ef", "98", "7a", "33", "54", "0b", "43", "ed", "cf", "ac", "62"},
                {"e4", "b3", "1c", "a9", "c9", "08", "e8", "95", "80", "df", "94", "fa", "75", "8f", "3f", "a6"},
                {"47", "07", "a7", "fc", "f3", "73", "17", "ba", "83", "59", "3c", "19", "e6", "85", "4f", "a8"},
                {"68", "6b", "81", "b2", "71", "64", "da", "8b", "f8", "eb", "0f", "4b", "70", "56", "9d", "35"},
                {"1e", "24", "0e", "5e", "63", "58", "d1", "a2", "25", "22", "7c", "3b", "01", "21", "78", "87"},
                {"d4", "00", "46", "57", "9f", "d3", "27", "52", "4c", "36", "02", "e7", "a0", "c4", "c8", "9e"},
                {"ea", "bf", "8a", "d2", "40", "c7", "38", "b5", "a3", "f7", "f2", "ce", "f9", "61", "15", "a1"},
                {"e0", "ae", "5d", "a4", "9b", "34", "1a", "55", "ad", "93", "32", "30", "f5", "8c", "b1", "e3"},
                {"1d", "f6", "e2", "2e", "82", "66", "ca", "60", "c0", "29", "23", "ab", "0d", "53", "4e", "6f"},
                {"d5", "db", "37", "45", "de", "fd", "8e", "2f", "03", "ff", "6a", "72", "6d", "6c", "5b", "51"},
                {"8d", "1b", "af", "92", "bb", "dd", "bc", "7f", "11", "d9", "5c", "41", "1f", "10", "5a", "d8"},
                {"0a", "c1", "31", "88", "a5", "cd", "7b", "bd", "2d", "74", "d0", "12", "b8", "e5", "b4", "b0"},
                {"89", "69", "97", "4a", "0c", "96", "77", "7e", "65", "b9", "f1", "09", "c5", "6e", "c6", "84"},
                {"18", "f0", "7d", "ec", "3a", "dc", "4d", "20", "79", "ee", "5f", "3e", "d7", "cb", "39", "48"}
        };


static const string CK[32] =
        {
                "00070e15", "1c232a31", "383f464d", "545b6269",
                "70777e85", "8c939aa1", "a8afb6bd", "c4cbd2d9",
                "e0e7eef5", "fc030a11", "181f262d", "343b4249",
                "50575e65", "6c737a81", "888f969d", "a4abb2b9",
                "c0c7ced5", "dce3eaf1", "f8ff060d", "141b2229",
                "30373e45", "4c535a61", "686f767d", "848b9299",
                "a0a7aeb5", "bcc3cad1", "d8dfe6ed", "f4fb0209",
                "10171e25", "2c333a41", "484f565d", "646b7279"
        };
static string FK0 = "A3B1BAC6";
static string FK1 = "56AA3350";
static string FK2 = "677D9197";
static string FK3 = "B27022DC";

//bit填充 128的倍数
//给明文添加\0
string padding_128bit(string m);

//非线性变换  返回二进制
//输入:4*8bit
//输出:4*8bit
string Tao(string A);

// 线性变换 返回二进制
//输入:32bit
//输出:32bit
string L(string b);

//L'函数
//输入:32bit
//输出:32bit
string L_(string b);

//合成置换
//输入:32bit
//输出:32bit
string T(string s);

//T'函数
//输入:32bit
//输出:32bit
string T_(string s);

//轮函数
//输入:4*32bit
//输出:4*32bit
string F(string x0, string x1, string x2, string x3, string rk);


//密钥扩展
//输入:4*32bit
//输出:32*8bit  轮密钥
int key_expand(string MK, vector<string> &rk_list);

//加密
//输入:4*32bit
//输出:4*32bit,十六进制字符串
string encrypt(string x, vector<string> rk_list);

//解密
//输入:4*32bit
//输出:4*32bit
string decrypt(string x, vector<string> rk_list);

//模式
/*
 * 1：ECB
 * 2:CBC
 * 3:CFB
 * 4:OFB
 * */
/*输入
 * mk 128bit
 * 输出:16进制字符串
 * */
string sm4_encrypt(string s, string mk, int mode = 1, string iv = "1234567812345678");

/*
 * 输入:16进制字符串
 * 输出:明文
 * */

string sm4_decrypt(string s, string mk, int mode = 1, string iv = "1234567812345678");


string _ecb_encrypt(string s, vector<string> rk_list);
string _ecb_decrypt(string s, vector<string> rk_list);
string _cbc_encrypt(string s, vector<string> rk_list,string iv);
string _cbc_decrypt(string s, vector<string> rk_list,string iv);
string _cfb_encrypt(string s, vector<string> rk_list,string iv);
string _cfb_decrypt(string s, vector<string> rk_list,string iv);
string _ofb_encrypt(string s, vector<string> rk_list,string iv);
string _ofb_decrypt(string s, vector<string> rk_list,string iv);
#endif //SM4_ALGORITHM_SM4_H
